<!--
db面板类型
tab+chart用来展示多维度的列表
-->
<template>
  <div class="dash-panel">
    <div class="dash-header">
      <div class="dash-header-title">
        <Icon :type="model.icon || 'stats-bars'"></Icon> {{title}}
        <span v-for="(item,index) in model.drill" class="badge-text" :class="{'badge-gray':index>=drillDeep}" :key="index">{{drillTitle(item,index)}}</span>
      </div>
      <slot name="tool"></slot>
      <div class="tab-box" v-if="tabPos==='top' && model.tabs && model.tabs.length">
        <span v-for="(tab,index) in model.tabs" @click="tabClick(index)" :class="{active:index===activeTab}" class="tab-item" :key="index">
          {{tab.name}}
        </span>
      </div>
      <div class="dash-header-right">
        <slot name="tool-right"></slot>
        <span class="badge-text badge-warn badge-empty" v-if="chartShow && data && !data.length && !fristLoad && !loading"><Icon type="alert"></Icon> 暂无数据</span>
        <span class="badge-text badge-loading" v-if="fristLoad">加载中...</span>
        <span class="badge-text badge-error" v-if="dataOverflow"><Icon type="alert"></Icon>数据超过最大条数（90）</span>
        <Button v-if="model.export" @click="actionExport" class="btn-tool" type="info" icon="code-download" size="small">导出</Button>
        <ButtonGroup v-if="enableMothly && main"  class="btn-time" shape="circle">
          <Button size="small" @click="monthly=false" :type="monthly?'default':'primary'">
            日
          </Button>
          <Button size="small" @click="monthly=true" :type="!monthly?'default':'primary'">
            月
          </Button>
        </ButtonGroup>
        <DatePicker :transfer="true" v-model="dateRange" :options="dateOptions" v-if="main" type="daterange" size="small" @on-change="rangeChange" placement="bottom-end"
          placeholder="选择统计范围" :clearable="false"></DatePicker>
      </div>
       <slot name="tool-line"></slot>
    </div>
    <div v-show="!chartShow" class="hide-text" :temp-data="dateOptions">{{chartShowTip}}</div>
    <div class="dash-body" v-if="chartShow">
      <Button v-if="model.drill" v-show="drillDeep>0" @click="drillBack" class="btn-back" type="success" icon="reply" size="small">返回</Button>
      <div class="tab-box" v-if="tabPos!=='top' && model.tabs && model.tabs.length">
        <div v-for="(tab,index) in model.tabs" @click="tabClick(index)" :class="{active:index===activeTab}" class="tab-item" :key="index">
          {{tab.name}}
        </div>
      </div>
      <slot></slot>
      <Chart :chartHeight="chartHeight" :loading="loading" :tab="activeTab" :freeze="chartFreeze" ref="chart" :selectable="model.select" @chartClick="chartClick" class="chart-item" :data="chartData" :model="chartModel"></Chart>
    </div>
  </div>
</template>

<script>
import Chart from "@/components/chart";
import $ from "@/common";
import Time from "@/common/time";
import Selector from "@/components/selector";
//一日事件长度，用于时间计算

const dayTs = 3600 * 1000 * 24;

export default {
  props: {
    model: {},
    extParam: {},
    main: {},
    tabPos: {
      default: "left"
    },
    enableImport: {},
    importData: {},
    param: {},
    mode: {},
    noDate: {},
    enableMothly: {
      default: true
    },
    chartShow: {
      default: true
    },
    chartShowTip: {
      default: "暂无数据"
    },
    chartHeight: {},
    dataFilter: {},
    charLoading: {
      default: false
    }
  },
  data() {
    return {
      activeTab: 0,
      //记录钻取路径的数据包括 index上级钻取目标索引 data上级钻取目标的数据 param上级钻取目标中得 option上级目标的option
      //用于记录历史数据，以恢复数据 功能待完善
      drillDataList: [],
      dataOverflow: false,
      drillDeep: 0,
      loadingCount: 0,
      //钻取参数，即钻取目标行的数据
      monthly: false,
      chartFreeze: false,
      loading: this.charLoading,
      //在上层更新过过滤条件之后再返回钻取数据，则钻取数据需要进行更新
      hasUpdate: false,
      fristLoad: true,
      dateRange: [Time.preMonth(), Time.toDate(new Date())],
      data: []
    };
  },
  watch: {
    monthly(v) {
      this.$emit("modeChange", v);
      this.getData();
    },
    charLoading(v) {
      this.loading = v;
    },
    //外部参数改变时查询数据，主要用于响应外部时间范围的改变
    param(v) {
      this.hasUpdate = true;
      this.getData();
    },
    mode(v) {
      this.monthly = v;
    },
    loadingCount(v) {
      if (this.loading && this.model.grids && v >= this.model.grids.length) {
        this.loading = false;
      }
    },
    importData(v) {
      this.$set(this, "data", v.data);
      if (v.grid) {
        for (let i in v.grid) {
          this.$refs.chart.setGridData(i, v.grid[i]);
        }
      }
      this.loading = false;
      if (this.fristLoad) {
        this.fristLoad = false;
      }
    }
  },
  computed: {
    key_start_time() {
      return this.model.keys && this.model.keys.start_time
        ? this.model.keys.start_time
        : "start_time";
    },
    key_end_time() {
      return this.model.keys && this.model.keys.end_time
        ? this.model.keys.end_time
        : "end_time";
    },
    title() {
      var title = this.model.title;
      return title;
    },
    drillParam() {
      return this.drillDataList.length
        ? this.drillDataList[this.drillDataList.length - 1].param
        : null;
    },
    drillIndex() {
      return this.drillDataList.length
        ? this.drillDataList[this.drillDataList.length - 1].index
        : null;
    },
    drillData() {
      return this.drillDataList.length
        ? this.drillDataList[this.drillDataList.length - 1]
        : null;
    },
    drillList() {
      var list = [];
      if (this.drillDeep) {
        for (let i = 0; i < this.drillDeep; i++) {
          if (this.model.drill[i]) {
            list.push(this.model.drill[i]);
          }
        }
      }
      return list;
    },
    postData() {
      var date = this.dateRange;
      return {
        [this.key_start_time]: date[0],
        [this.key_end_time]: date[1],
        ...this.param
      };
    },
    chartModel() {
      if (
        this.drillDeep <= 0 ||
        !this.model.drill ||
        !this.model.drill[this.drillDeep - 1]
      ) {
        return this.model;
      } else {
        return this.model.drill[this.drillDeep - 1];
      }
    },
    fetchPath() {
      return this.monthly
        ? this.chartModel.path_monthly || this.chartModel.path
        : this.chartModel.path;
    },
    dateOptions() {
      if (!this.monthly || 1) {
        return {
          shortcuts: [
            {
              text: "本周",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 7);
                return [start, end];
              }
            },
            {
              text: "本月",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * (start.getDate() - 1));
                return [start, end];
              }
            },
            {
              text: "近1月",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 30);
                return [start, end];
              }
            },
            {
              text: "上月",
              value() {
                var end = new Date();
                var start = new Date();
                var year = start.getFullYear();
                var month = start.getMonth();
                var end_1 = `${year}-${month + 1}-01`;
                if (month === 0) {
                  month = 11;
                  year--;
                } else {
                  month--;
                }
                start = new Date(`${year}-${month + 1}-01`);
                end.setTime(new Date(end_1) - dayTs);
                return [start, end];
              }
            },
            {
              text: "近3月",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 90);
                return [start, end];
              }
            }
          ]
        };
      } else {
        return {
          shortcuts: [
            {
              text: "近3月",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 90);
                return [start, end];
              }
            },
            {
              text: "近6月",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 180);
                return [start, end];
              }
            },
            {
              text: "本年",
              value() {
                const end = new Date();
                const start = new Date();
                start.setTime(start.getTime() - dayTs * 365);
                return [start, end];
              }
            }
          ]
        };
      }
    },
    chartData() {
      return this.data;
    }
  },
  methods: {
    //导出响应
    actionExport() {},
    tabClick(index) {
      this.activeTab = index;
    },
    drillTitle(item, index) {
      return $.composeValue(
        item.title,
        this.drillDataList[index] && this.drillDataList[index].param
      );
    },
    resize() {
      this.$refs.chart.resize();
    },
    getData() {
      this.loading = true;
      if (this.chartShow) {
        if (this.enableImport) {
          this.$emit("fetching");
        } else {
          var postData = this.getPostData();
          return $.link(this.fetchPath, { ...postData, ...this.extParam })
            .then(res => {
              //先查询主数据，确定x轴数据后再查询副轴数据
              var data = res.data;
              if (this.model.date_axis) {
                var tsStart = Time.toTs(this.dateRange[0]);
                var tsEnd = Time.toTs(this.dateRange[1]);
                var tsSet = {};
                while (tsStart < tsEnd) {
                  tsSet[Time.toDate(tsStart)] = true;
                  tsStart += 1000 * 60 * 60 * 24;
                }
                for (let i in data) {
                  tsSet[data[i][this.model.x_axis]] = false;
                }
                for (let i in tsSet) {
                  if (tsSet[i]) {
                    data.push({
                      [this.model.x_axis]: i
                    });
                  }
                }
              }
              this.$set(this, "data", data);
              this.$emit("updateData", this.data);
            })
            .finally(() => {
              if (!this.model.grids || !this.model.grids.length) {
                this.loading = false;
              } else {
                this.$nextTick(() => {
                  this.getGridData(postData);
                });
              }
            });
        }
      } else {
        return new Promise(resolve => {
          resolve();
        });
      }
    },
    getGridData(postData) {
      this.loading = true;
      this.loadingCount = 0;
      if (this.model.grids && this.model.grids.length) {
        for (let i in this.model.grids) {
          let grid = this.model.grids[i];
          if (grid.main_data) {
            this.$nextTick(() => {
              this.$refs.chart.setGridData(i, this.data);
              this.loadingCount++;
            });
          } else {
            let path = this.monthly
              ? grid.path_monthly || grid.path
              : grid.path;
            let data = $.copy(postData);
            if (grid.mark === 1) {
              data = {
                pageSize: 90,
                period_start: data.start_time,
                period_end: data.end_time
              };
            }
            data = $.setObj(data, this.param);
            if (grid.key) {
              if (grid.key.start_time) {
                data[grid.key.start_time] = data.start_time;
                delete data.start_time;
              }
              if (grid.key.end_time) {
                data[grid.key.end_time] = data.end_time;
                delete data.end_time;
              }
            }
            $.link(path, { ...data, ...this.extParam })
              .then(res => {
                var data = res.data;
                data = data.data || data;
                this.$refs.chart.setGridData(i, data);
              })
              .finally(() => {
                this.loadingCount++;
              });
          }
        }
      }
    },
    getPostData() {
      var data = this.postData || {};
      if (
        data[this.key_start_time] &&
        (typeof data[this.key_start_time] === "number" ||
          data[this.key_start_time].constructor === Date)
      ) {
        data[this.key_start_time] = Time.toDate(data[this.key_start_time]);
      }
      if (
        data[this.key_end_time] &&
        (typeof data[this.key_end_time] === "number" ||
          data[this.key_end_time].constructor === Date)
      ) {
        data[this.key_end_time] = Time.toDate(data[this.key_end_time]);
      }
      if (this.drillParam) {
        if (this.chartModel.param) {
          for (let i in this.chartModel.param) {
            data[i] = this.drillParam[this.chartModel.param[i]];
          }
        }
      }
      if (this.noDate) {
        delete data[this.key_end_time];
        delete data[this.key_start_time];
      }
      return data;
    },
    //选择范围改变
    rangeChange(v) {
      //通过点击选择的时间范围在该事件触发时还是旧值，因此需要在下个时间点中刷新数据
      this.$nextTick(() => {
        this.$emit("paramChange", {
          [this.key_start_time]: this.dateRange[0],
          [this.key_end_time]: this.dateRange[1]
        });
        this.getData();
      });
    },
    drillBack() {
      //钻取返回判断，若在上级的钻取中进行了数据条件的更新，则返回上级钻取数据时将重新搜索上级数据
      if (!this.hasUpdate && this.drillData) {
        this.chartFreeze = true;
        this.$set(this, "data", this.drillData.data);
        this.$refs.chart.forceOption(this.drillData.option);
        this.drillDeep--;
        this.drillDataList.pop();
        this.$nextTick(() => {
          this.chartFreeze = false;
        });
      } else {
        this.drillDeep--;
        this.drillDataList.pop();
        this.$set(this, "data", []);
        this.getData();
      }
    },
    drillChart() {
      this.drillDeep++;
      this.$set(this, "data", []);
      this.getData();
    },
    chartClick(param) {
      this.$emit("chartClick", param);
      if (param.componentType === "series" && this.model.drill) {
        if (this.drillDeep < this.model.drill.length) {
          this.drillDataList.push({
            index: param.dataIndex,
            data: $.copy(this.data),
            option: this.$refs.chart.getOption(),
            param: $.copy(this.data[param.dataIndex])
          });
          this.hasUpdate = false;
          this.drillChart();
        }
      }
    }
  },
  created() {
    var dataHandle = this.getData();
    dataHandle &&
      dataHandle.finally(() => {
        this.fristLoad = false;
      });
  },
  components: {
    Chart,
    Selector
  }
};
</script>

<style lang="less">
.dash-panel {
  padding-left: 8px;

  .total-box {
    display: inline-block;
    padding: 4px 8px;
    color: #585858;
    .total-value {
      color: #168cf3;
      border-left: 1px solid #dddee1;
      margin-left: 6px;
      padding-left: 4px;
      .ivu-icon {
        margin-right: 2px;
      }
    }
    .total-rate {
      width: 100px;
      display: inline-block;
      border-radius: 2px;
      background: #4f6b92;
      color: #fff;
      padding: 0;
      overflow: hidden;
      font-weight: bold;
      margin-left: 4px;
      margin-right: -8px;
      .total-rate-value {
        display: inline-block;
        overflow: visible;
        width: 0;
        background: #50c3e8;
        padding: 0;
        transition: width 0.3s;
      }
    }
    .total-label {
      display: inline-block;
      overflow: hidden;
    }
  }
  .filter-box {
    display: inline-block;
    padding: 0 4px;
    color: #585858;
    .filter-box-title {
      border-right: 1px solid #dddee1;
      padding-left: 4px;
      padding-right: 4px;
      margin-right: 2px;
    }
    .filter-label {
      display: inline-block;
      padding-left: 4px;
      border-left: 1px solid #dddee1;
    }
  }
  .btn-back {
    position: absolute;
    z-index: 5;
    top: 28px;
    right: 0px;
  }
  .btn-time {
    margin-right: 8px;
  }
  .badge-warn,
  .badge-loading {
    position: absolute;
    top: 50%;
    left: 50%;
  }

  .tab-item {
    padding: 4px 8px;
    background: #f5f7f9;
    margin: 4px 0;
    text-align: center;
    border-radius: 2px;
    min-width: 80px;
    display: inline-block;
    cursor: pointer;
    &:hover {
      background: #f9fafb;
      &.active {
        background: #61c4e4;
      }
    }
    &.active {
      background: #61c4e4;
      color: #fff;
    }
  }
}

.dash-header {
  height: 26px;
  .ivu-date-picker {
    width: 170px;
    border-radius: 0 3px 3px 0;
    .ivu-input-small {
      padding-right: 0;
    }
  }
  .btn-time {
    margin-right: -6px;
    .ivu-btn {
      z-index: 2;
    }
  }
  .ivu-btn-group:not(.ivu-btn-group-vertical)
    > .ivu-btn:first-child:not(:last-child) {
    border-radius: 4px 0 0 4px;
    padding: 2px 10px;
  }
  .ivu-btn-group:not(.ivu-btn-group-vertical)
    > .ivu-btn:last-child:not(:first-child) {
    border-radius: 0;
    padding: 2px 10px;
  }

  .btn-tool {
    margin-right: 8px;
  }
  .dash-header-title {
    padding: 3px 16px 3px 0;
    font-size: 14px;
    float: left;
  }
  .dash-header-right {
    float: right;
    .badge-text .ivu-icon {
      margin-right: 8px;
    }
  }
  .badge-text {
    margin: 0 4px;
    z-index: 5;
  }
  .ivu-btn-small {
    padding: 2px 16px;
  }
  .tab-box {
    padding: 0 8px;
    display: inline-block;
    .tab-item {
      padding: 2px 8px;
    }
  }
}
.hide-text {
  font-size: 14px;
  text-align: center;
  padding: 32px;
  color: #e99f68;
}

.dash-body {
  position: relative;
  clear: both;
  display: flex;
  overflow-x: visible;
  .tab-box {
    width: 90px;
    padding-right: 16px;
  }
  .chart-item {
    flex: 1;
  }
}
</style>
